home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 138 / 138.xpi / chrome / stumbleupon.jar / content / prefetcher.js < prev    next >
Text File  |  2009-08-03  |  13KB  |  509 lines

  1. function su_Prefetcher()
  2. {
  3.     //!!! We need to get the mouse cursor load clock image to not spin.
  4.     // background:
  5.     // The cursor is set by the docshell's progress listener implementation.
  6.     // http://lxr.mozilla.org/seamonkey/source/docshell/base/nsDocShell.cpp#4778
  7.     // http://lxr.mozilla.org/aviary101branch/source/docshell/base/nsDocShell.cpp#4537
  8.  
  9.     //###  private attributes
  10.     var service;
  11.     try {
  12.         service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
  13.     }
  14.     catch (e) {
  15.         // seamonkey kludge
  16.         service = su_service;
  17.     }
  18.     this.ds = service.getDatastore();
  19.     this.URIsIndex = -1;
  20.     this.URIs = new Array();
  21.     this.referrersByURI = new Object();
  22.     this.redirectTargetsByURI = new Object();
  23.     this.passCountsByURI = new Object();
  24.     this.statesByURI = new Object();
  25.     this.urlDetailByURI = new Object();
  26.     this.httpStatusesByURI = new Object();
  27.     this.target = null;
  28.     this.id = su_Prefetcher.instanceCount++;
  29.     this.browserId = "su_prefetcher" + this.id;
  30.     this.passCount = 1;
  31.     this.URIsTopIndex = 0;
  32.     this.URIsBottomIndex = -1;
  33.     this.eventListenerListsByEventId = new Object();
  34.     this.queueLocked = false;
  35.     
  36.     //###  public attributes
  37.     
  38.     this.mode = "complete";
  39.     this.pass1TimeoutInterval = 10000;
  40.     this.pass2TimeoutInterval = 30000;
  41.     this.pass3TimeoutInterval = 120000;
  42.     this.passMax = 3;
  43.     this.disabled = false;
  44.     this.delayedStartInterval = 0;
  45.     this.pauseForScriptRedirectInterval = 800;
  46.     this.continuous = true;
  47.     this.maintainHistory = false;
  48.     this.allTargetsPrefetched = true;
  49.     this.fetchAheadDepth = -1;
  50.  
  51.     //###  private methods
  52.  
  53.     this._start = function()
  54.     {
  55.         if (this.disabled)
  56.             return;
  57.         if (this.allTargetsPrefetched)
  58.             return;
  59.         
  60.         var browser = document.getElementById(this.browserId);
  61.         if (browser)
  62.         {
  63.             this._logRedirectTarget();
  64.             
  65.             document.getElementById("main-window").removeChild(browser);
  66.         }
  67.         
  68.         var found = false;
  69.         var uri;
  70.         while ((! found) && ((this.URIsIndex + 1) <= this.URIsBottomIndex))
  71.         {
  72.             this.URIsIndex++;
  73.             uri = this.URIs[this.URIsIndex];
  74.             if ((this.statesByURI[uri] == "new") || 
  75.                         ((this.passCount > 1) && (this.passCountsByURI[uri] > 1) &&
  76.                         (this.passCountsByURI[uri] < this.passMax) &&
  77.                         (this.statesByURI[uri] == "timed-out")))
  78.             {
  79.                 found = true;
  80.             }
  81.         }
  82.         if (! found)
  83.         {
  84.             this.passCount++;
  85.             if (this.passCount > this.passMax)
  86.             {
  87.                 this.target = null;
  88.                 this.allTargetsPrefetched = true;
  89.                 this._dispatchEvent("done");
  90.                 if (this.ds.getValue("@log_prefetch_progress"))
  91.                     su_log("prefetching done");
  92.             }
  93.             else if (! this.allTargetsPrefetched)
  94.             {
  95.                 this.target = null;
  96.                 this.URIsIndex = this.URIsTopIndex - 1;
  97.                 this._start();
  98.             }
  99.             return;
  100.         }
  101.         
  102.         this.target = uri;
  103.         
  104.         // The technique of deleting/creating a browser each time and 
  105.         // applying to it the style attribute below is derived from the 
  106.         // Cooliris extension with permission from its developers. -- JW
  107.         browser = document.createElement("browser");
  108.         browser.setAttribute("id", this.browserId);
  109.         browser.setAttribute("type", "content");
  110.         browser.setAttribute("src", "about:blank");
  111.         browser.setAttribute("style", "visibility:hidden;overflow:auto;border:0px solid black;background-color:white;width:0px;height:0px;");
  112.         
  113.         document.getElementById("main-window").appendChild(browser);
  114.         
  115.         browser.docShell.allowJavascript = true;
  116.         browser.docShell.allowMetaRedirects = true;
  117.         browser.docShell.allowAuth = false;
  118.         browser.docShell.allowPlugins = false;
  119.         browser.docShell.allowSubframes = true;
  120.         
  121.         if (this.mode == "DOM")
  122.         {
  123.             browser.addEventListener("DOMContentLoaded", function () { this.handleDocumentLoad("DOMContentLoaded"); }, true);
  124.         }
  125.         browser.addProgressListener(this);
  126.         
  127.         try {
  128.             browser.loadURI(this.target, su_get_nsiuri(this.referrersByURI[this.target]), null);
  129.         } catch (e) {
  130.             su_log_error("prefetch load error", e, this.target);
  131.         }
  132.         
  133. //        if (browser.contentDocument.contentType != "text/html")
  134. //        {
  135. //            browser.stop();
  136. //            this.URIsIndex++;
  137. //            this._start();
  138. //        }
  139.         
  140.         var interval;
  141.         switch (this.passCountsByURI[this.target])
  142.         {
  143.             case 1:   interval = this.pass1TimeoutInterval;  break;
  144.             case 2:   interval = this.pass2TimeoutInterval;  break;
  145.             case 3:   interval = this.pass3TimeoutInterval;  break;
  146.         }
  147.         
  148.         if (this.ds.getValue("@log_prefetch_progress"))
  149.             su_log("prefetching " + (this.URIsIndex + 1) + " of " + this.URIs.length, this.target, "pass " + this.passCount + " with timeout " + interval + "ms");
  150.  
  151.         this.timer = setTimeout(function (prefetcher) { prefetcher._finishPrefetch("timeout"); }, interval, this)
  152.     }
  153.     
  154.     this._finishPrefetch = function (from)
  155.     {
  156.         if (this.ds.getValue("@log_prefetch_progress"))
  157.             su_log("finish", from);
  158.         var state;
  159.         switch (from)
  160.         {
  161.             case "timeout":  state = "timed-out"; break;
  162.             case "pause":
  163.             case "stop":
  164.             case "advance":  state = "new";       break;
  165.             case "skip":     state = "skipped";   break;
  166.             case "load":     state = "fetched";   break;
  167.         }
  168.         this.statesByURI[this.target] = state;
  169.         
  170.         if (this.timer)
  171.         {
  172.             clearTimeout(this.timer);
  173.         }
  174.         if (this.pauseForScriptRedirectTimer)
  175.         {
  176.             clearTimeout(this.pauseForScriptRedirectTimer);
  177.         }
  178.  
  179.         if ((from == "load") || (from == "timeout"))
  180.             this.passCountsByURI[this.target]++;
  181.         
  182.         if (from == "stop")
  183.         {
  184.             var browser = document.getElementById(this.browserId);
  185.             if (browser)
  186.             {
  187.                 document.getElementById("main-window").removeChild(browser);
  188.             }
  189.         }
  190.  
  191.         if ((from == "pause") && (from == "stop"))
  192.             return;
  193.  
  194.         if (this.continuous)
  195.         {
  196.             setTimeout(function (prefetcher) { prefetcher._start(); }, this.pauseForScriptRedirectInterval, this);
  197.         }
  198.         else
  199.         {
  200.             this._logRedirectTarget();
  201.             this.pauseForScriptRedirectTimer = setTimeout(function (prefetcher) { prefetcher._logRedirectTarget; }, this.pauseForScriptRedirectInterval, this);
  202.         }
  203.     }
  204.  
  205.     this._logRedirectTarget = function ()
  206.     {
  207.         if (! this.target)
  208.             return;
  209.         
  210.         if (this.ds.getValue("@log_prefetch_progress"))
  211.             su_log("logging " + (this.URIsIndex + 1) + " of " + this.URIs.length, this.target, "pass " + this.passCount, "state " + this.statesByURI[this.target]);
  212.  
  213.         var browser = document.getElementById(this.browserId);
  214.         if (browser && browser.contentDocument && browser.contentDocument.location)
  215.         {
  216.             this.redirectTargetsByURI[this.target] = browser.contentDocument.location.href;
  217.         }
  218.     }
  219.     
  220.     this._updateBottomIndex = function ()
  221.     {
  222.         if (this.fetchAheadDepth == -1)
  223.         {
  224.             this.URIsBottomIndex = this.URIs.length - 1;
  225.         }
  226.         else
  227.         {
  228.             this.URIsBottomIndex = this.URIsTopIndex + this.fetchAheadDepth - 1;
  229.             if (this.URIsBottomIndex > this.URIs.length - 1)
  230.             {
  231.                 this.URIsBottomIndex = this.URIs.length - 1;
  232.             }
  233.         }
  234.     }
  235.     
  236.     this._dispatchEvent = function (eventId)
  237.     {
  238.         var listeners = this.eventListenerListsByEventId[eventId];
  239.         if (! listeners)
  240.             return;
  241.         
  242.         var i;
  243.         for (i = 0; i < listeners.length; i++)
  244.         {
  245.             var event = new Object();
  246.             event.target = this;
  247.             listeners[i](event);
  248.         }
  249.     }
  250.  
  251.  
  252.     //###  privileged methods
  253.  
  254.     this.handleDocumentLoad = function (from)
  255.     {
  256.         var browser = document.getElementById(this.browserId);
  257.         if ((((from == "DOMContentLoaded") && (this.mode == "DOM")) ||
  258.                     ((from == "progress-stop") && (this.mode == "complete"))) &&
  259.                     browser && browser.contentDocument &&
  260.                     browser.contentDocument.location &&
  261.                     (browser.contentDocument.location.href != "about:blank"))
  262.         {
  263.             this._finishPrefetch("load");
  264.         }
  265.     }
  266.     
  267.     this.setQueueLock = function (state)
  268.     {
  269.         this.queueLocked = state;
  270.     }
  271.     
  272.     this.addTarget = function (urlDetail)
  273.     {
  274.         if (this.queueLocked)
  275.             return;
  276.         
  277.         if (! this.statesByURI[urlDetail.url])
  278.         {
  279.             this.urlDetailByURI[urlDetail.url] = urlDetail;
  280.             this.statesByURI[urlDetail.url] = "new";
  281.             this.allTargetsPrefetched = false;
  282.             this.URIs.push(urlDetail.url);
  283.             this.passCount = 1;
  284.             this.passCountsByURI[urlDetail.url] = 1;
  285.             this._updateBottomIndex();
  286.             this.referrersByURI[urlDetail.url] = urlDetail.referrer;
  287.         }
  288.     }
  289.     
  290.     this.skipCurrentTarget = function ()
  291.     {
  292.         this._finishPrefetch("skip");
  293.     }
  294.     
  295.     this.advancePastTarget = function (uri)
  296.     {
  297.         var i;
  298.         this._finishPrefetch("advance");
  299.         for (i = 0; i < this.URIs.length; i++)
  300.         {
  301.             if (this.URIs[i] == uri)
  302.             {
  303.                 if (i >= this.URIsBottomIndex)
  304.                 {
  305.                     this.allTargetsPrefetched = true;
  306.                     break;
  307.                 }
  308.                 else
  309.                 {
  310.                     this.passCount = 1;
  311.                     this.allTargetsPrefetched = false;
  312.                     this.URIsTopIndex = i + 1;
  313.                     if (this.URIsIndex < this.URIsTopIndex)
  314.                     {
  315.                         this.URIsIndex = this.URIsTopIndex;
  316.                     }
  317.                     this._updateBottomIndex();
  318.                 }
  319.             }
  320.         }
  321.     }
  322.  
  323.     this.clearTargets = function ()
  324.     {
  325.         this.URIsIndex = -1;
  326.         this.allTargetsPrefetched = true;
  327.         this.URIs = new Array();
  328.         if (! this.maintainHistory)
  329.         {
  330.             this.clearHistory();
  331.         }
  332.     }
  333.     
  334.     this.clearHistory = function ()
  335.     {
  336.         this.passCountsByURI = new Object();
  337.         this.redirectTargetsByURI = new Object();
  338.         this.statesByURI = new Object();
  339.         this.referrersByURI = new Object();
  340.         this.httpStatusesByURI = new Object();
  341.         this.urlDetailByURI = new Object();
  342.     }
  343.  
  344.     this.getRedirectTarget = function (uri)
  345.     {
  346.         var target = this.redirectTargetsByURI[uri];
  347.         return (target) ? target : uri;
  348.     }
  349.     
  350.     this.setRedirectTarget = function (originalTarget, currentTarget)
  351.     {
  352.         this.redirectTargetsByURI[originalTarget] = currentTarget;
  353.     }
  354.     
  355.     this.getCurrentTarget = function ()
  356.     {
  357.         return this.target;
  358.     }
  359.  
  360.     this.setHttpResponseStatus = function (target, status)
  361.     {
  362.         var prev = parseInt(this.httpStatusesByURI[target]);
  363.         var cur = parseInt(status);
  364.         if ((! prev) || (prev > cur))
  365.             this.httpStatusesByURI[target] = status;
  366.     }
  367.     
  368.     this.getHttpResponseStatus = function (target)
  369.     {
  370.         return (this.httpStatusesByURI[target]) ? this.httpStatusesByURI[target] : null;
  371.     }
  372.     
  373.     this.start = function ()
  374.     {
  375.         this.disabled = false;
  376.         setTimeout(function (prefetcher) { prefetcher._start(); }, this.delayedStartInterval, this);
  377.     }
  378.  
  379.     this.stop = function ()
  380.     {
  381.         this.disabled = true;
  382.         this._finishPrefetch("stop");
  383.         this.target = null;
  384.         this.URIsIndex = -1;
  385.     }
  386.  
  387.     this.pause = function ()
  388.     {
  389.         this.disabled = true;
  390.         this._finishPrefetch("pause");
  391.         if ((this.URIsIndex >= this.URIsTopIndex) && (! this.allTargetsPrefetched))
  392.         {
  393.             this.URIsIndex--;
  394.         }
  395.     }
  396.     
  397.     this.addEventListener = function (eventId, listener)
  398.     {
  399.         var listeners = this.eventListenerListsByEventId[eventId];
  400.         if (! listeners)
  401.         {
  402.             listeners = new Array();
  403.             this.eventListenerListsByEventId[eventId] = listeners;
  404.         }
  405.         else
  406.         {
  407.             this.removeEventListener(eventId, listener);
  408.         }
  409.         listeners.push(listener);
  410.     }
  411.     
  412.     this.removeEventListener = function (eventId, listener)
  413.     {
  414.         var listeners = this.eventListenerListsByEventId[eventId];
  415.         var i;
  416.         for (i = 0; i < listeners.length; i++)
  417.         {
  418.             if (listener == listeners[i])
  419.             {
  420.                 listeners = listeners.splice(i, 1);
  421.                 break;
  422.             }
  423.         }
  424.     }
  425.     
  426.     this.QueryInterface = function (iid)
  427.     {
  428.         if (!iid.equals(Components.interfaces.nsIWebProgressListener) &&
  429.             !iid.equals(Components.interfaces.nsISupportsWeakReference) && // not implemented
  430.             !iid.equals(Components.interfaces.nsISupports))
  431.         {
  432.             throw Components.errors.NS_ERROR_NO_INTERFACE;
  433.         }
  434.  
  435.         return this;
  436.     }
  437.  
  438.     this.onLocationChange = function (aWebProgress, aRequest, aLocation) {}
  439.  
  440.     this.onProgressChange = function (aWebProgress, aRequest,
  441.                          aCurSelfProgress, aMaxSelfProgress,
  442.                          aCurTotalProgress, aMaxTotalProgress)
  443.     {
  444.         window.setCursor("auto");
  445.         setTimeout(function (window) { window.setCursor("auto"); }, 0, window);
  446.     }
  447.  
  448.     this.onStateChange = function(aWebProgress, aRequest, aStateFlags, aStatus)
  449.     {
  450.         const nsIWPL = Components.interfaces.nsIWebProgressListener;
  451.         var originalUrl;
  452.         
  453.         window.setCursor("auto");
  454.         setTimeout(function (window) { window.setCursor("auto"); }, 0, window);
  455.  
  456.         if (! (aStateFlags & nsIWPL.STATE_IS_REQUEST))
  457.             return;
  458.         
  459.         if (aStateFlags & nsIWPL.STATE_START)
  460.         {
  461.             // Kill alert and prompt on prefetch pages. -- JW
  462.             var win;
  463.             if (aWebProgress.DOMWindow.wrappedJSObject)
  464.                 win = aWebProgress.DOMWindow.wrappedJSObject;
  465.             else
  466.                 win = aWebProgress.DOMWindow;
  467.             
  468.             win.alert = function (){};
  469.             win.prompt = function (){};
  470.             win.confirm = function (){};
  471.             win.open = function (){};
  472.             win.moveTo = function (){};
  473.             win.resizeTo = function (){};
  474.             win.sizeToContent = function (){};
  475.  
  476.             this._dispatchEvent("progress-start");
  477.         }
  478.         
  479.         try {
  480.             if (aWebProgress.DOMWindow != aWebProgress.DOMWindow.top)
  481.                 return;
  482.         } catch (e) { return; } // ignore error accessing DOMWindow.top
  483.         
  484.         if (aStateFlags & nsIWPL.STATE_STOP)
  485.         {
  486.             try {
  487.                 var browser = document.getElementById(this.browserId);
  488.                 var channel = browser.docShell.currentDocumentChannel;
  489.                 
  490.                 var status = channel.responseStatus;
  491.                 this.setHttpResponseStatus(this.target, status);
  492.             } catch (e) {}
  493.             // Notify the prefetcher that the document load is complete.
  494.             this.handleDocumentLoad("progress-stop");
  495.         }
  496.     }
  497.  
  498.     this.onStatusChange = function (aWebProgress, aRequest, aStatus, aMessage)
  499.     {
  500.         window.setCursor("auto");
  501.         setTimeout(function (window) { window.setCursor("auto"); }, 0, window);
  502.     }
  503.  
  504.     this.onSecurityChange = function (aWebProgress, aRequest, aState) {}
  505. }
  506. //###  static attributes
  507. su_Prefetcher.instanceCount = 0;
  508.  
  509.